package com.fy.opengltest.renderPicture;

import android.content.Context;
import android.net.Uri;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

import com.fy.opengltest.R;
import com.fy.opengltest.ShaderUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * Created by yao.fu on 17-1-23.
 */
public class GLRendererCirclePicture implements GLSurfaceView.Renderer {

    private Uri uri = null;
    private Context context;
    private int programId;
    private int aPositionHandle;
    private int uMatrixHandle;

    private int textureId;
    private int uTextureSamplerHandle;
    private int aTextureCoordHandle;

    int screenWidth = 1;
    int screenHeight = 1;

    private FloatBuffer mVertexBuffer;
    private ShortBuffer indexBuffer;
    private FloatBuffer mTextureVertexBuffer;
    int mNumIndices;


    private final float[] projectionMatrix = new float[16];

    public GLRendererCirclePicture(Context context) {
        this.context = context;
        initVertexData(0f, 0f, 180, 1.0f);
    }

    public GLRendererCirclePicture(Context applicationContext, Uri uri) {
        this.uri = uri;
    }


    private void initVertexData(float offset_x, float offset_y, int sectors, float radius) {
        final int nodeCount = sectors + 2;

        float vertexs[] = new float[nodeCount * 3];
        float texcoords[] = new float[nodeCount * 2];
        short indices[] = new short[nodeCount * 3];

        int offset_texcoord = 0;
        int offset_vertex = 0;
        //for center point
        texcoords[offset_texcoord++] = 0.5f;
        texcoords[offset_texcoord++] = 0.5f;
        vertexs[offset_vertex++] = offset_x;
        vertexs[offset_vertex++] = offset_y;
        vertexs[offset_vertex++] = 0;

        //for circle point
        for (int i = 0; i < sectors + 1; i++) {
            float angleInRadians = ((float) (i) / (float) sectors) * ((float) Math.PI * 2f);

            texcoords[offset_texcoord++] = 0.5f + radius * (float) (Math.sin(angleInRadians));
            texcoords[offset_texcoord++] = 0.5f + radius * (float) (Math.cos(angleInRadians));

            vertexs[offset_vertex++] = offset_x + (float) Math.sin(angleInRadians);
            vertexs[offset_vertex++] = offset_y + (float) Math.cos(angleInRadians);
            vertexs[offset_vertex++] = 0;
        }

        for (int i = 0; i < sectors + 1; i++) {
            indices[i * 3] = 0;
            indices[i * 3 + 1] = (short) (i + 1);
            indices[i * 3 + 2] = (short) (i + 2);
        }

        indices[indices.length - 1] = 1;

        // initialize gl_vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (# of coordinate values * 4 bytes per float)
                vertexs.length * 4);
        bb.order(ByteOrder.nativeOrder());
        FloatBuffer vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(vertexs);
        vertexBuffer.position(0);

        // initialize gl_vertex byte buffer for shape coordinates
        ByteBuffer cc = ByteBuffer.allocateDirect(
                texcoords.length * 4);
        cc.order(ByteOrder.nativeOrder());
        FloatBuffer texBuffer = cc.asFloatBuffer();
        texBuffer.put(texcoords);
        texBuffer.position(0);

        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(
                // (# of coordinate values * 2 bytes per short)
                indices.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        indexBuffer = dlb.asShortBuffer();
        indexBuffer.put(indices);
        indexBuffer.position(0);

        mTextureVertexBuffer = texBuffer;
        mVertexBuffer = vertexBuffer;
        mNumIndices = indices.length;
    }


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.vertex_shader_render_picture);
        String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.fragment_shader_render_picture);
        programId = ShaderUtils.createProgram(vertexShader, fragmentShader);
        aPositionHandle = GLES20.glGetAttribLocation(programId, "aPosition");
        uMatrixHandle = GLES20.glGetUniformLocation(programId, "uMatrix");

        if (null != uri)
            textureId = TextureHelper.loadTexture(context, uri);
        else
            textureId = TextureHelper.loadTexture(context, R.raw.dome190_24402400);//R.raw.demo_pic);

        uTextureSamplerHandle = GLES20.glGetUniformLocation(programId, "sTexture");
        aTextureCoordHandle = GLES20.glGetAttribLocation(programId, "aTexCoord");


//        mVertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
//                .order(ByteOrder.nativeOrder())
//                .asFloatBuffer()
//                .put(vertexData);
//        vertexBuffer.position(0);
//
//        indexBuffer = ByteBuffer.allocateDirect(indexData.length * 2)
//                .order(ByteOrder.nativeOrder())
//                .asShortBuffer()
//                .put(indexData);
//        indexBuffer.position(0);
//
//        textureVertexBuffer = ByteBuffer.allocateDirect(textureVertexData.length * 4)
//                .order(ByteOrder.nativeOrder())
//                .asFloatBuffer()
//                .put(textureVertexData);
//        textureVertexBuffer.position(0);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
//        BitmapFactory.Options options = new BitmapFactory.Options();
//        options.inJustDecodeBounds = true;
//        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.test, options);
//        updateProjection(bitmap.getWidth(), bitmap.getHeight(), width, height);
//        bitmap.recycle();

        //updateProjection(9, 16, width, height);
        updateProjection(1, 1, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glUseProgram(programId);
        GLES20.glUniformMatrix4fv(uMatrixHandle, 1, false, projectionMatrix, 0);
        GLES20.glEnableVertexAttribArray(aPositionHandle);
        GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false, 12, mVertexBuffer);


        GLES20.glEnableVertexAttribArray(aTextureCoordHandle);
        GLES20.glVertexAttribPointer(aTextureCoordHandle, 2, GLES20.GL_FLOAT, false, 8, mTextureVertexBuffer);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);

        GLES20.glUniform1i(uTextureSamplerHandle, 0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices, GLES20.GL_UNSIGNED_SHORT, indexBuffer);

    }

    private void updateProjection(float videoWidth, float videoHeight, int screenWidth, int screenHeight) {
        float screenRatio = (float) screenWidth / screenHeight;
        float videoRatio = (float) videoWidth / videoHeight;
        if (videoRatio > screenRatio) {
            Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -videoRatio / screenRatio, videoRatio / screenRatio, -1f, 1f);
        } else
            Matrix.orthoM(projectionMatrix, 0, -screenRatio / videoRatio, screenRatio / videoRatio, -1f, 1f, -1f, 1f);
    }
}
